package component

import (
	"context"
	"fmt"
	"github.com/hyperway/pkg/config"
	"github.com/hyperway/pkg/logger"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

var shutdownSignals = []os.Signal{os.Interrupt, os.Kill, syscall.SIGKILL, syscall.SIGSTOP,
	syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGILL, syscall.SIGTRAP,
	syscall.SIGABRT, syscall.SIGSYS, syscall.SIGTERM}

// ServerPool server池，一般情况下，会有管理服务器和网关服务器两种类型的服务器
type ServerPool struct {
	// key：服务器名称或者id（唯一标识），value：服务器实例
	servers map[string]*Server
	// 服务发现实例，用于发现注册中心的服务
	discover Discover
	// 服务启动的的节点
	waiter *sync.WaitGroup
}

// Server 服务器实例
type Server struct {
	ServerId    string    // 服务器名称或者id（唯一标识）
	WebListener           // Web服务实例的包装，如echo框架的包装
	MvcMVCC     *sync.Map // 存储注册的Api，具有多版本控制，key：Api的唯一标识，value：Api的元数据，key相同但版本不同的Api共享一个存储单元，存储单元中包含了版本信息
	Writer      ServerResponseWriter
}

// SetDiscover 设置服务发现实例
func (p *ServerPool) SetDiscover(discover Discover) {
	p.discover = discover
}

// NewServerPool 创建ServerPool实例
func NewServerPool() *ServerPool {
	pool := ServerPool{
		servers: make(map[string]*Server, 2),
		waiter:  &sync.WaitGroup{},
	}
	return &pool
}

func (p *ServerPool) NewServer(config *config.Configuration, f NewWebListenerFunc, writer ServerResponseWriter) *Server {
	listener := f(config)
	ins := &Server{ServerId: listener.Name(), WebListener: listener, Writer: writer}
	ins.MvcMVCC = new(sync.Map)
	p.servers[ins.ServerId] = ins
	return ins
}

func (p *ServerPool) prepare() error {
	for _, prepare := range PrepareLifecycle() {
		logger.Infof("Prepare lifecycle title: %s is ready.", prepare.Title())
		if err := prepare.OnPrepare(); err != nil {
			logger.Errorf("Prepare lifecycle title: %s error with %s", prepare.Title(), err.Error())
			return err
		}
		logger.Infof("Prepare lifecycle title: %s completed.", prepare.Title())
	}
	for _, initialize := range InitializeLifecycle() {
		if err := initialize.OnInit(); err != nil {
			return err
		}
	}
	return nil
}

func (p *ServerPool) start() error {
	// 生命周期准备阶段
	err := p.prepare()
	if err != nil {
		logger.Errorf("ServerPool prepare error with %s", err.Error())
		return err
	}
	p.waiter.Add(1)
	// 服务器启动时发现
	go p.discover.Once(p, p.waiter)
	p.waiter.Wait()
	// 服务器运行时发现
	go p.discover.Ongoing(p)

	// 服务器启动
	for name, server := range p.servers {
		// 服务器初始化
		server.OnInit()
		filters := PreFilters()
		// 自定义的前置过滤器
		server.AddPreRequestFilters(filters...)
		go func(name string, listener WebListener) {
			if err := listener.Start(); err != nil {
				panic(err)
			}
		}(name, server)
	}
	return nil
}

func (p *ServerPool) destroy(ctx context.Context) error {

	for _, shutdown := range ShutdownLifecycle() {
		logger.Infof("Shutdown lifecycle title: %s is ready.", shutdown.Title())
		if err := shutdown.OnFinalize(ctx); err != nil {
			logger.Errorf("Shutdown lifecycle title: %s error with %s", shutdown.Title(), err.Error())
		} else {
			logger.Infof("Shutdown lifecycle title: %s completed.", shutdown.Title())
		}
	}

	for _, destroy := range DestroyLifecycle() {
		fmt.Printf("Destroy lifecycle title: %s is ready.\n", destroy.Title())
		if err := destroy.OnDestroy(ctx); err != nil {
			fmt.Printf("Destroy lifecycle title: %s error with %s\n", destroy.Title(), err.Error())
		} else {
			fmt.Printf("Destroy lifecycle title: %s completed.\n", destroy.Title())
		}
	}
	return nil
}

func (p *ServerPool) GetServer(name string) *Server {
	return p.servers[name]
}

func (p *ServerPool) stop(timeout time.Duration) {
	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()
	p.destroy(ctx)
}

func (p *ServerPool) StartGraceful() {
	quit := make(chan os.Signal, 1)

	go func() {
		defer func() {
			if r := recover(); r != nil {
				quit <- os.Interrupt
			}
		}()
		if err := p.start(); err != nil {
			quit <- os.Interrupt
		}
	}()

	signal.Notify(quit, shutdownSignals...)
	sig := <-quit
	logger.Info("receive signal: ", sig)

	p.stop(10 * time.Second)
}
